From a1584b36b29f067846b55ba747cc559ce60b809f Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 21 Nov 2005 18:10:35 +0100 Subject: [PATCH] Change semantics of gnttab_transfer to take the page away from the calling domain, even on error (except for special error GNTST_bad_page). This has a knock-on advantage of simplifying Linux's netback driver. Signed-off-by: Keir Fraser --- .../drivers/xen/netback/netback.c | 29 ++++------------- xen/common/grant_table.c | 31 ++++++++++--------- xen/common/page_alloc.c | 4 ++- xen/include/public/grant_table.h | 10 ++++-- 4 files changed, 33 insertions(+), 41 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 800ce32e36..2941119f6b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -99,27 +99,6 @@ static unsigned long alloc_mfn(void) return mfn; } -static void free_mfn(unsigned long mfn) -{ - unsigned long flags; - struct xen_memory_reservation reservation = { - .extent_start = &mfn, - .nr_extents = 1, - .extent_order = 0, - .domid = DOMID_SELF - }; - spin_lock_irqsave(&mfn_lock, flags); - if ( alloc_index != MAX_MFN_ALLOC ) - mfn_list[alloc_index++] = mfn; - else { - int ret; - ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, - &reservation); - BUG_ON(ret != 1); - } - spin_unlock_irqrestore(&mfn_lock, flags); -} - static inline void maybe_schedule_tx_action(void) { smp_mb(); @@ -306,14 +285,18 @@ static void net_rx_action(unsigned long unused) netif->stats.tx_packets++; /* The update_va_mapping() must not fail. */ - BUG_ON(mcl[0].result != 0); + BUG_ON(mcl->result != 0); /* Check the reassignment error code. */ status = NETIF_RSP_OKAY; if (gop->status != 0) { DPRINTK("Bad status %d from grant transfer to DOM%u\n", gop->status, netif->domid); - free_mfn(old_mfn); + /* + * Page no longer belongs to us unless GNTST_bad_page, + * but that should be a fatal error anyway. + */ + BUG_ON(gop->status == GNTST_bad_page); status = NETIF_RSP_ERROR; } irq = netif->irq; diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index f9f7a3e33b..8586996f0b 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -714,26 +714,18 @@ gnttab_transfer( /* Read from caller address space. */ if ( unlikely(__copy_from_user(&gop, &uop[i], sizeof(gop))) ) { - /* Caller error: bail immediately. */ DPRINTK("gnttab_transfer: error reading req %d/%d\n", i, count); - return -EFAULT; + (void)__put_user(GNTST_bad_page, &uop[i].status); + return -EFAULT; /* This is *very* fatal. */ } /* Check the passed page frame for basic validity. */ page = &frame_table[gop.mfn]; if ( unlikely(!pfn_valid(gop.mfn) || IS_XEN_HEAP_FRAME(page)) ) { - /* Caller error: bail immediately. */ DPRINTK("gnttab_transfer: out-of-range or xen frame %lx\n", (unsigned long)gop.mfn); - return -EINVAL; - } - - /* Find the target domain. */ - if ( unlikely((e = find_domain_by_id(gop.domid)) == NULL) ) - { - DPRINTK("gnttab_transfer: can't find domain %d\n", gop.domid); - (void)__put_user(GNTST_bad_domain, &uop[i].status); + (void)__put_user(GNTST_bad_page, &uop[i].status); continue; } @@ -752,15 +744,14 @@ gnttab_transfer( x = y; if (unlikely((x & (PGC_count_mask|PGC_allocated)) != (1 | PGC_allocated)) || unlikely(_nd != _d)) { - /* Caller error: bail immediately. */ DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p," " caf=%08x, taf=%" PRtype_info "\n", (void *) page_to_pfn(page), d, d->domain_id, unpickle_domptr(_nd), x, page->u.inuse.type_info); spin_unlock(&d->page_alloc_lock); - put_domain(e); - return -EINVAL; + (void)__put_user(GNTST_bad_page, &uop[i].status); + continue; } __asm__ __volatile__( LOCK_PREFIX "cmpxchg8b %2" @@ -779,6 +770,16 @@ gnttab_transfer( spin_unlock(&d->page_alloc_lock); + /* Find the target domain. */ + if ( unlikely((e = find_domain_by_id(gop.domid)) == NULL) ) + { + DPRINTK("gnttab_transfer: can't find domain %d\n", gop.domid); + (void)__put_user(GNTST_bad_domain, &uop[i].status); + page->count_info &= ~(PGC_count_mask|PGC_allocated); + free_domheap_page(page); + continue; + } + spin_lock(&e->page_alloc_lock); /* @@ -797,6 +798,8 @@ gnttab_transfer( spin_unlock(&e->page_alloc_lock); put_domain(e); (void)__put_user(GNTST_general_error, &uop[i].status); + page->count_info &= ~(PGC_count_mask|PGC_allocated); + free_domheap_page(page); continue; } diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index d5f1ed0263..1890db8e81 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -645,7 +645,9 @@ void free_domheap_pages(struct pfn_info *pg, unsigned int order) } else { - /* Freeing an anonymous domain-heap page. */ + /* Freeing anonymous domain-heap pages. */ + for ( i = 0; i < (1 << order); i++ ) + pg[i].u.free.cpumask = CPU_MASK_NONE; free_heap_pages(pfn_dom_zone_type(page_to_pfn(pg)), pg, order); drop_dom_ref = 0; } diff --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h index eb1ccdd935..0ee07dd4ff 100644 --- a/xen/include/public/grant_table.h +++ b/xen/include/public/grant_table.h @@ -215,9 +215,12 @@ typedef struct gnttab_dump_table { } gnttab_dump_table_t; /* - * GNTTABOP_transfer_grant_ref: Transfer to a foreign domain. The - * foreign domain has previously registered the details of the transfer. - * These can be identified from , a grant reference. + * GNTTABOP_transfer_grant_ref: Transfer to a foreign domain. The + * foreign domain has previously registered its interest in the transfer via + * . + * + * Note that, even if the transfer fails, the specified page no longer belongs + * to the calling domain *unless* the error is GNTST_bad_page. */ #define GNTTABOP_transfer 4 typedef struct { @@ -269,6 +272,7 @@ typedef struct { #define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/ #define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ #define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ +#define GNTST_bad_page (-9) /* Specified page was invalid for op. */ #define GNTTABOP_error_msgs { \ "okay", \ -- 2.30.2